/*
 * Copyright 2009 Jamie Gennis
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.code.ggdi;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.shell.log.ServletContextTreeLogger;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.servlet.GuiceServletContextListener;
import com.google.inject.servlet.ServletModule;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.http.HttpServlet;

/**
 * A {@code GuiceServletContextListener} that automatically discovers Guice
 * modules that are needed by the GWT modules being used.
 *
 * The main GWT module should be specified in the {@code com.google.code.ggdi.
 * gwtModule} initialization property.
 *
 * @author jgennis
 */
public class GgdiContextListener extends GuiceServletContextListener {

  static final String MODULE_NAME_PARAMETER = "com.google.code.ggdi.gwtModule";

  String moduleName;

  ServletContext servletContext;

  @Override
  public void contextInitialized(ServletContextEvent servletContextEvent) {
    ServletContext context = servletContextEvent.getServletContext();
    moduleName = context.getInitParameter(MODULE_NAME_PARAMETER);
    if (moduleName == null) {
      throw new RuntimeException("The initialization parameter '" + MODULE_NAME_PARAMETER +
          "' was not specified");
    }
    servletContext = servletContextEvent.getServletContext();
    super.contextInitialized(servletContextEvent);
  }

  @Override
  protected Injector getInjector() {
    TreeLogger treeLogger = new ServletContextTreeLogger(servletContext);
    try {
      ModuleDef moduleDef = Utils.getModuleDef(treeLogger, moduleName);
      List<Module> modules = Utils.getGuiceModules(moduleDef);
      Map<String, Class<? extends HttpServlet>> bindings = Utils.getServletBindings(treeLogger,
          modules);
      Module servletModule = createServletModule(bindings);
      modules.add(servletModule);
      Injector injector = Guice.createInjector(modules);
      return injector;
    } catch (ConfigurationException ex) {
      throw new RuntimeException(ex);
    }
  }

  Module createServletModule(final Map<String, Class<? extends HttpServlet>> bindings) {
    Module servletModule = new ServletModule() {

      @Override
      protected void configureServlets() {
        for (Map.Entry<String, Class<? extends HttpServlet>> binding : bindings.entrySet()) {
          String path = binding.getKey();
          Class<? extends HttpServlet> servlet = binding.getValue();
          serve(path).with(servlet);
        }
      }
    };
    return servletModule;
  }
}
